package cc.shacocloud.mirage.restful;

import cc.shacocloud.mirage.restful.bind.annotation.HttpMethod;
import cc.shacocloud.mirage.restful.bind.annotation.PathPatterns;
import cc.shacocloud.mirage.restful.bind.annotation.RequestMapping;
import cc.shacocloud.mirage.utils.collection.ArrayUtil;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;

import java.util.Arrays;
import java.util.Objects;

/**
 * 请求映射信息
 *
 * @author 思追(shaco)
 * @see RequestMapping
 */
@Getter
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public final class RequestMappingInfo {
    
    /**
     * 匹配路径匹配模式
     *
     * @see RequestMapping#patterns()
     */
    private final PathPatterns pathPatterns;
    
    /**
     * 路径表达式
     *
     * @see RequestMapping#path()
     */
    private final String[] paths;
    
    /**
     * 请求方式
     *
     * @see RequestMapping#method()
     */
    private final HttpMethod[] methods;
    
    /**
     * 请求类型
     *
     * @see RequestMapping#consumes()
     */
    private final String[] consumes;
    
    /**
     * 可接受类型
     *
     * @see RequestMapping#produces()
     */
    private final String[] produces;
    
    /**
     * 建造者对象
     */
    @Contract(" -> new")
    public static @NotNull Builder builder() {
        return new Builder();
    }
    
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        RequestMappingInfo that = (RequestMappingInfo) o;
        return pathPatterns == that.pathPatterns && Arrays.equals(paths, that.paths) && Arrays.equals(methods, that.methods) && Arrays.equals(consumes, that.consumes) && Arrays.equals(produces, that.produces);
    }
    
    @Override
    public int hashCode() {
        int result = Objects.hash(pathPatterns);
        result = 31 * result + Arrays.hashCode(paths);
        result = 31 * result + Arrays.hashCode(methods);
        result = 31 * result + Arrays.hashCode(consumes);
        result = 31 * result + Arrays.hashCode(produces);
        return result;
    }
    
    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder("{");
        
        if (Objects.nonNull(this.pathPatterns)) {
            builder.append(" pathPatterns ").append(this.pathPatterns);
        }
        
        if (!ArrayUtil.isEmpty(this.paths)) {
            builder.append(" paths ").append(Arrays.toString(this.paths));
        }
        
        if (!ArrayUtil.isEmpty(this.methods)) {
            builder.append(", methods ").append(Arrays.toString(this.methods));
        }
        
        if (!ArrayUtil.isEmpty(this.consumes)) {
            builder.append(", consumes ").append(Arrays.toString(this.consumes));
        }
        if (!ArrayUtil.isEmpty(this.produces)) {
            builder.append(", produces ").append(Arrays.toString(this.produces));
        }
        builder.append(" }");
        return builder.toString();
    }
    
    public static class Builder {
        private PathPatterns pathPatterns = PathPatterns.PATH;
        private String[] paths;
        private HttpMethod[] methods = new HttpMethod[]{};
        private String[] consumes = new String[]{};
        private String[] produces = new String[]{};
        
        public Builder pathPatterns(PathPatterns pathPatterns) {
            this.pathPatterns = pathPatterns;
            return this;
        }
        
        public Builder paths(String[] paths) {
            this.paths = paths;
            return this;
        }
        
        public Builder methods(HttpMethod[] methods) {
            this.methods = methods;
            return this;
        }
        
        public Builder consumes(String[] consumes) {
            this.consumes = consumes;
            return this;
        }
        
        public Builder produces(String[] produces) {
            this.produces = produces;
            return this;
        }
        
        public RequestMappingInfo build() {
            if (ArrayUtil.isEmpty(paths)) {
                throw new IllegalArgumentException("paths 必须不为空！");
            }
            return new RequestMappingInfo(pathPatterns, paths, methods, consumes, produces);
        }
    }
}
